package com.prb.consumer.config;

import com.prb.consumer.register.RegisterContext;
import com.prb.register.factory.RpcRegistryFactory;
import com.prb.register.register.RpcRegistryHandler;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.File;
import java.net.URL;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

@Component
public class ServerScanLoader implements InitializingBean {

    @Autowired
    private RegisterContext registerContext;

    // 扫描 到 的服务列表
    private static List<String> serverClassList = new CopyOnWriteArrayList<>();

    //服务主机 map 集合  serverName ==> hostList
    public static Map<String , List<String>> serverHostMap = new ConcurrentHashMap<String , List<String>>();

    // 主机列表
    public static Set<String> serverHostList = new HashSet<>();

    @Autowired
    private RpcRegistryFactory rpcRegistryFactory;



    public void afterPropertiesSet() throws Exception {

        String initPackage = "com.prb.common.service";
        loadServiceClass(initPackage);
        if(serverClassList.isEmpty()){
            throw new RuntimeException("扫描到 的服务列表为空");
        }

        //进行服务发现
        for (String serverClass : serverClassList) {
            discoveryServer(serverClass);
        }

        //初始化 客户端 调用环境
        ClientContext.initClientContext(serverHostList);
    }


    /**
     * 找到provider包下所有的实现类名，并放进providerClassList里
     */
    private static void loadServiceClass(final String packageName) {
        // 所以得用匿名内部类来解决
        // 这里由classLoader的getResource方法获得包名并封装成URL形式
        URL url = new Object() {
            public URL getPath() {
                String packageDir = packageName.replace(".", "/");
                URL o = this.getClass().getClassLoader().getResource(packageDir);
                return o;
            }

        }.getPath();
        // 将该包名转换为File格式，用于以下判断是文件夹还是文件，若是文件夹则递归调用本方法，
        // 若不是文件夹则直接将该provider的实现类的名字放到providerClassList中
        File dir = new File(url.getFile());
        File[] fileArr = dir.listFiles();
        for (File file : fileArr) {
            if (file.isDirectory()) {
                loadServiceClass(packageName + "." + file.getName());
            } else {
                serverClassList.add(packageName + "." + file.getName().replace(".class", ""));
            }
        }

    }


    /**
     * 服务发现，放入缓存 , 并对 服务节点进行监听
     * @param serverName
     * @throws Exception
     */
    public void discoveryServer(String serverName) throws Exception {


        List<String> serverList = registerContext.discovery(serverName);

        //为服务添加监听 ， 当服务对应的主机列表发生改变时，更新客户端的主机列表
        registerContext.addNodeChangeListener(serverName);

        serverHostList.addAll(serverList);

        serverHostMap.put(serverName , serverList);
    }


}
